package com.xlf.service.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xlf.common.auth.util.SecurityUtils;
import com.xlf.common.core.exception.BizException;
import com.xlf.common.core.pojo.vo.UserVO;
import com.xlf.common.core.util.BeanCopyUtils;
import com.xlf.common.core.util.ServletUtils;
import com.xlf.common.core.util.StringUtils;
import com.xlf.common.redis.service.RedisCache;
import com.xlf.pojo.constant.Constants;
import com.xlf.service.blog.domain.*;
import com.xlf.service.blog.domain.dto.AddArticleDTO;
import com.xlf.service.blog.domain.dto.ArticleQueryDTO;
import com.xlf.service.blog.domain.dto.EditArticleDTO;
import com.xlf.service.blog.domain.vo.ArticleInfoVO;
import com.xlf.service.blog.mapper.*;
import com.xlf.service.blog.service.ArticleService;
import com.xlf.service.system.service.impl.CommonUserVOService;
import jodd.typeconverter.Convert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xlf.common.core.constant.ArticleConstants.ARTICLE_VIEW;
/**
* @author 小新
* @description 针对表【t_article】的数据库操作Service实现
* @createDate 2023-07-08 15:48:07
*/
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
    implements ArticleService{

    @Resource
    ArticleMapper articleMapper;

    @Resource
    TypeMapper typeMapper;

    @Resource
    RedisCache redisCache;

    @Resource
    CommentMapper commentMapper;

    @Resource
    ThumbsMapper thumbsMapper;

    @Resource
    FollowMapper followMapper;

    @Resource
    CollectionMapper collectionMapper;

    @Autowired
    CommonUserVOService commonUserVOService;


    @Override
    public List<Article> getPage(Article article) {

        List<Article> articles = Optional.ofNullable(lambdaQuery()
                        .setEntity(article)
                        .like(StringUtils.isNotEmpty(article.getSearchValue()), Article::getArticleTitle, article.getSearchValue())
                        .between(StringUtils.isNotEmpty(article.getParams()) &&
                                        article.getParams().get("beginTime") != null && article.getParams().get("endTime") != null,
                                Article::getCreateTime, article.getParams().get("beginTime"),
                                article.getParams().get("endTime"))
                        .list())
                .orElse(new ArrayList<>());
        if(StringUtils.isEmpty(articles))
            return articles;

        articles.forEach(item -> {
            builder(item).addType().addAuthor();
        });
        return articles;
    }

    @Override
    public List<Article> getPage(ArticleQueryDTO articleQueryDto) {


        QueryChainWrapper<Article> wrapper = query();

        wrapper.select("id",
                "user_id",
                "SUBSTRING(article_content, 1, 100) as articleContent",  // 使用 SUBSTRING 函数,只查出100个字
                "article_title",
                "article_cover",
                "create_time",
                "article_read_num",
                "is_top",
                "article_type",
                "type_id",
                "status");

        wrapper.orderByDesc("is_top")
                .eq(articleQueryDto.getTypeId() != null,"type_id",articleQueryDto.getTypeId())
                .eq("status", com.xlf.common.core.constant.Constants.NORMAL)
                .eq(articleQueryDto.getProblemId() !=null, "problem_id",articleQueryDto.getProblemId())
                .eq(StringUtils.isNotNull(articleQueryDto.getUserId()),"user_id",articleQueryDto.getUserId())
                .like(StringUtils.isNotEmpty(articleQueryDto.getSearchKey()),"article_title",articleQueryDto.getSearchKey());

        //最热
        if(articleQueryDto.getSeq() == 2)
            wrapper.orderByDesc("article_read_num");

        //最新
        wrapper.orderByDesc("id");

        //权限
        privacy(wrapper);

        //我的
        if(StringUtils.isNotNull(articleQueryDto.getMe()) &&  true == articleQueryDto.getMe()){
            Object userId = SecurityUtils.getUserId();
            wrapper.eq("user_id",userId);
        }

        //收藏
        if(StringUtils.isNotNull(articleQueryDto.getStar()) && true == articleQueryDto.getStar()){
            Object userId = SecurityUtils.getUserId();
            List<Collection> collections = collectionMapper.selectList(new LambdaQueryWrapper<Collection>()
                    .select(Collection::getArticleId)
                    .eq(Collection::getUserId, userId));
            if(StringUtils.isEmpty(collections))
                return new ArrayList<>();
            wrapper.in("id",collections.stream().map(Collection::getArticleId).collect(Collectors.toSet()));
        }


        List<Article> list = wrapper.list();

        if(StringUtils.isEmpty(list))
            return new ArrayList<>();
        list.forEach(item->{
             builder(item)
                     .addType()
                     .addAuthor()
                     .incrementReadNum(0L)
                     .addCollectionNum()
                     .addThumbsNum()
                     .isCollection()
                     .addCommentNum()
                     .isThumbs();
        });

        return list;
    }

    /**
     * 是否公开
     * @param wrapper
     */
    private void privacy(LambdaQueryWrapper<Article> wrapper) {

        Long userId = null;
        try {
             userId = (Long) SecurityUtils.getUserId();
        } catch (Exception e) {
//            e.printStackTrace();
        }

        if(userId == null){
            //仅可以查看公开
            wrapper.eq(Article::getAuth, Constants.Article.PUBLIC.getCode());
        }else{
            //公开和私密
            Long finalUserId = userId;
            wrapper.and(o->o.eq(Article::getAuth,Constants.Article.PUBLIC.getCode()).or(i-> i.eq(Article::getAuth,Constants.Article.PRIVATE.getCode()).eq(Article::getUserId, finalUserId)));
        }
    }


    /**
     * 是否公开
     * @param wrapper
     */
    private void privacy(QueryChainWrapper<Article> wrapper) {

        Long userId = null;
        try {
            userId = (Long) SecurityUtils.getUserId();
        } catch (Exception e) {
//            e.printStackTrace();
        }

        if(userId == null){
            //仅可以查看公开
            wrapper.eq("auth",Constants.Article.PUBLIC.getCode());
        }else{
            //公开和私密
            Long finalUserId = userId;
            wrapper.and(o->o.eq("auth",Constants.Article.PUBLIC.getCode())
                    .or(i-> i.eq("auth",Constants.Article.PRIVATE.getCode()).eq("user_id", finalUserId)));
        }
    }

    @Override
    public Article getArticleById(Long articleId) {

        LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Article::getStatus, com.xlf.common.core.constant.Constants.NORMAL)
                .eq(Article::getId,articleId);
        privacy(wrapper);
        Article article = getOne(wrapper);

        return builder(article)
                .addType()
                .addAuthor()
                .isFollow()
                .incrementReadNum(1L)
                .build();
    }


    @Override
    public void saveArticle(AddArticleDTO article) {

        Long userId = (Long) SecurityUtils.getUserId();
        Article article1 = BeanCopyUtils.copyObject(article, Article.class);
        article1.setArticleReadNum(0);
        article1.setUserId(userId);
        article1.setIsTop(0);
        article1.setIsRecommend(0);
        save(article1);
    }

    @Override
    public void updateArticle(EditArticleDTO article) {

        Long userId = (Long) SecurityUtils.getUserId();

        Article t = getById(article.getId());

        if(t == null)
            throw new BizException("文章不存在！");

        if(!userId.equals(t.getUserId()) && !SecurityUtils.isAdmin(userId))
            throw new BizException("无权限修改！");

        updateById(BeanCopyUtils.copyObject(article, Article.class));

    }

    @Override
    public boolean deleteArticle(Long id) {

        Article article = getOne(new LambdaQueryWrapper<Article>()
                .eq(Article::getId,id)
                .select(Article::getUserId));

        if(article == null)
            throw new BizException("文章不存在！");

        Long userId = (Long)SecurityUtils.getUserId();
        if(!SecurityUtils.isAdmin(userId) && !userId.equals(article.getUserId()))
            throw new BizException("没有权限进行删除！");

        return lambdaUpdate().set(Article::getStatus, com.xlf.common.core.constant.Constants.EXCEPTION).eq(Article::getId,id).update();
    }

    @Override
    public void collection(Long articleId) {

        if(!articleMapper.exists(new LambdaQueryWrapper<Article>().eq(Article::getId, articleId)))
            throw new BizException("文章不存在！");

        Object userId = SecurityUtils.getUserId();

        LambdaQueryWrapper<Collection> wrapper = new LambdaQueryWrapper<Collection>().eq(Collection::getUserId, userId)
                .eq(Collection::getArticleId, articleId);
        if(collectionMapper.exists(wrapper)){
            collectionMapper.delete(wrapper);
        }else{
            Collection collection = new Collection();
            collection.setArticleId(articleId);
            collection.setUserId((Long) userId);
            collectionMapper.insert(collection);
        }
    }



    @Override
    public void thumbs(Long articleId) {

        if(!articleMapper.exists(new LambdaQueryWrapper<Article>().eq(Article::getId, articleId)))
            throw new BizException("文章不存在！");

        Object userId = SecurityUtils.getUserId();

        LambdaQueryWrapper<Thumbs> wrapper = new LambdaQueryWrapper<Thumbs>().eq(Thumbs::getUserId, userId)
                .eq(Thumbs::getArticleId, articleId);
        if(thumbsMapper.exists(wrapper)){
            thumbsMapper.delete(wrapper);
        }else{
            Thumbs thumbs = new Thumbs();
            thumbs.setArticleId(articleId);
            thumbs.setUserId((Long) userId);
            thumbsMapper.insert(thumbs);
        }
    }

    @Override
    public void follow(Long userById) {
        UserVO userInfo = commonUserVOService.getUserInfo(userById);
        if(userInfo == null)
            throw new BizException("用户不存在！");

        Object userId = SecurityUtils.getUserId();

        LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>().eq(Follow::getUserId, userId)
                .eq(Follow::getUserById, userById);
        if(followMapper.exists(wrapper)){
            followMapper.delete(wrapper);
        }else{
            Follow follow = new Follow();
            follow.setUserById(userById);
            follow.setUserId((Long) userId);
            followMapper.insert(follow);
        }

    }

    @Override
    public List<Article> getRecentlyArticle() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();


        QueryChainWrapper<Article> wrapper = query();

        wrapper.select("id",
                "user_id",
                "article_title",
                "article_cover",
                "create_time",
                "article_read_num",
                "is_top",
                "article_type",
                "type_id",
                "status");

        wrapper.eq("status", com.xlf.common.core.constant.Constants.NORMAL)
                .eq("user_id",userId);

        //最新
        wrapper.orderByDesc("id");

        //权限
        privacy(wrapper);

        wrapper.last("limit 10");

        List<Article> list = wrapper.list();

        if(StringUtils.isEmpty(list))
            return new ArrayList();
        list.forEach(item->{
            builder(item)
                    .addType()
                    .addCollectionNum()
                    .addThumbsNum()
                    .addCommentNum();
        });

        return list;

    }

    @Override
    public ArticleInfoVO getArticleInfo() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();

        Long articleNum = articleMapper.selectCount(new LambdaQueryWrapper<Article>()
                .eq(Article::getUserId, userId)
                .eq(Article::getStatus, com.xlf.common.core.constant.Constants.NORMAL)
                .eq(Article::getAuth, Constants.Article.PUBLIC));

        Long followNum = followMapper.selectCount(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getUserId, userId));

        Long byFollowNum = followMapper.selectCount(new LambdaQueryWrapper<Follow>()
                .eq(Follow::getUserById, userId));

        ArticleInfoVO articleInfoVO = new ArticleInfoVO();

        articleInfoVO.setArticleNum(Optional.of(articleNum).orElse(0L).intValue());

        articleInfoVO.setFollowNum(Optional.of(followNum).orElse(0L).intValue());

        articleInfoVO.setFansNum(Optional.of(byFollowNum).orElse(0L).intValue());


        return articleInfoVO;

    }

    @Override
    public Article getArticle(Long articleId) {

        Article article = getById(articleId);

        if(article == null)
            throw new BizException("文章不存在！");

        return builder(article).addAuthor().addType().build();
    }


    public class ArticleBuilder implements Serializable {

        private Article article;

        ArticleBuilder(Article article){
            this.article = article;
        }

        public ArticleBuilder addType(){
            if(article.getTypeId() != null)
                article.setType(typeMapper.selectById(article.getTypeId()));
            return this;
        }

        public ArticleBuilder addAuthor(){
            if(article.getUserId() != null)
                article.setAuthor(commonUserVOService.getUserInfo(article.getUserId()));
            return this;
        }

        public ArticleBuilder isThumbs(){
            article.setThumbs(0);
            try {
                Object userId = SecurityUtils.getUserId();
                LambdaQueryWrapper<Thumbs> wrapper = new LambdaQueryWrapper<Thumbs>().eq(Thumbs::getUserId, userId)
                        .eq(Thumbs::getArticleId, article.getId());
                if(thumbsMapper.exists(wrapper)){
                    article.setThumbs(1);
                }
            } catch (Exception e) {
            }
            return this;
        }

        public ArticleBuilder isCollection(){
            article.setCollection(0);
            try {
                Object userId = SecurityUtils.getUserId();
                LambdaQueryWrapper<Collection> wrapper = new LambdaQueryWrapper<Collection>().eq(Collection::getUserId, userId)
                        .eq(Collection::getArticleId, article.getId());
                if(collectionMapper.exists(wrapper)){
                    article.setCollection(1);
                }
            } catch (Exception e) {

            }

            return this;
        }

        public ArticleBuilder isFollow(){
            article.setFollow(0);
            try {
                Object userId = SecurityUtils.getUserId();
                LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>().eq(Follow::getUserId, userId)
                        .eq(Follow::getUserById, article.getUserId());
                if(followMapper.exists(wrapper)){
                    article.setFollow(1);
                }
            } catch (Exception e) {

            }

            return this;
        }

        public ArticleBuilder incrementReadNum(Long isIncrement){
            //自增
            Long increment = redisCache.mapIncrement(ARTICLE_VIEW, article.getId().toString(), isIncrement);

            if(increment == null)
                increment = 0L;
            //无缓存 //
            if(article.getArticleReadNum() > increment.intValue()){

                article.setArticleReadNum(article.getArticleReadNum() + isIncrement.intValue());

                //高并发下有数据一致性问题
                redisCache.setCacheMapValue(ARTICLE_VIEW, article.getId().toString(), article.getArticleReadNum());
            }
            else
                article.setArticleReadNum(increment.intValue());

            return this;
        }

        public ArticleBuilder addCommentNum() {
            article.setArticleCommentNum(0);
            Long count = commentMapper.selectCount(new LambdaQueryWrapper<Comment>()
                    .eq(Comment::getTypeId,article.getId())
                    .eq(Comment::getCommentType, 1));
            if(null != count)
                article.setArticleCommentNum(count.intValue());
            return this;
        }

        public ArticleBuilder addThumbsNum(){
            article.setThumbsNum(0);
            Long count = thumbsMapper.selectCount(new LambdaQueryWrapper<Thumbs>().eq(Thumbs::getArticleId, article.getId()));
            if(null != count)
                article.setThumbsNum(count.intValue());
            return this;
        }

        public ArticleBuilder addCollectionNum(){
            article.setCollectionNum(0);
            Long count = collectionMapper.selectCount(new LambdaQueryWrapper<Collection>().eq(Collection::getArticleId, article.getId()));
            if(null != count)
                article.setCollectionNum(count.intValue());
            return this;
        }

        public Article build(){
            return article;
        }
    }


    public ArticleBuilder builder(Article article){
        if(article == null)
            throw new BizException("文章不存在");
        return new ArticleBuilder(article);
    }


}




